/***************************************************************************
 //* Foxit Software Inc.
 //* Copyright(C) 2005-2014, all rights reserved.
 //*
 //* The following code is copyrighted and contains proprietary information
 /* and trade secrets of Foxit Software Inc.
 **************************************************************************
 */
define(function (require, exports, module) {
    var PDFPageView = require('./PDFPageView');
    require('./LayoutInfo');
    var ProgressiveViewerGenerator = require('./ProgressiveViewerGenerator.js');
    var SinglePageViewLayout = require('./SinglePageViewLayout');
    require("../Config");
    var Config = WebPDF.Config;
    var PDFRect = require("../Math/Rect.js");
    /**
     * Enum for scroll bar type, both custom scroll bar and browser native scroll bar are supported.
     * @enum
     */
    WebPDF.PDFView.ScrollBarType = {
        CUSTOM_SCROLL_BAR : 0,
        NATIVE_SCROLL_BAR : 1
    };

    //Zoom constants
    WebPDF.ZOOM_FIT_WIDTH = 'FitWidth';
    WebPDF.ZOOM_IN =  'in';
    WebPDF.ZOOM_OUT = 'out';
    WebPDF.ZOOM_FIT_PAGE = 'FitPage';
    WebPDF.ZOOM_FIT_VISIBLE = 'FitVisible';
    WebPDF.ZOOM_ACTUAL_SIZE = 'ActualSize';
    WebPDF.ZOOM_NUMBER = 'Number';
    
    
   
    /**
     * @description Create an new PDFDocView object.
     * @class Represents a control used for displaying a Document.
     * @constructor
     * @param {WebPDF.IPDFDocument} pdfDoc  The reference to the current PDF document object.
     * @param {WebPDF.IPageViewRender} pageViewRender  The render object.
     * @param {String} mainFrameID  ID of the mainframe div.
     * @param {WebPDF.PDFView.LayoutInfo} layoutInfo  Layout information.
     * @param {WebPDF.ReaderApp} readerApp The reference to the current app instance.
     */
    var PDFDocView = function (pdfDoc, pageViewRender, mainFrameID, layoutInfo, readerApp) {
        if (pdfDoc == null)
            $.error("pdfDoc is null!");
        
        this.pdfDoc = pdfDoc;
        this.pageViewRender = pageViewRender;
        this.layoutInfo = layoutInfo;
        this.readerApp = readerApp;           
        
        this.docViewContainerID = mainFrameID + "_ViewContainer";
        //_leftDocContainerID and _rightDocContainerID are for the view mode of two page layout;
        this.leftDocContainerID = mainFrameID + "_ViewContainer_1";
        this.rightDocContainerID = mainFrameID + "_ViewContainer_2";
        this.mainFrameID = mainFrameID;
            
            
        //scroll api
        this.scrollApi = null;
        //width of doc view
        this.docViewWidth = 0;
        //height of doc view
        this.docViewHeight = 0;
        // 视图区域的padding值
        this.paddingVertical = 0;
        this.paddingHorizontal = 0;
        //视口偏移；
        this.docViewOffsetTop = 0;
        this.docViewOffsetLeft = 0;
        //current page index           
       
        this.curZoomMode = null;              
           // _pageIndexTooltipDivId = "fx_mobile_pageindex_tooltip",
           // _tooltipTimeout = null,
        this.progressiveViewerGenerator = null;            
      
        this.scrollBarWidth = 18;
        
        this._isModified = false;
        /**
         * reset loaded state of all of pages
         * @private
         */
        /*function _resetPageLoadedState() {
            var pageCnt = _self.getPageCount();
            for (var i = 0; i < pageCnt; i++) {
                var pgeView = _self.getPageView(i);
                if (pgeView.isContentCreated())
                    pgeView.setPageLoaded(false);
            }
        }*/
       
       
         return new PDFDocViewInner(this);
    };
    
     var PDFDocViewInner = Backbone.View.extend({        
        initialize : function(){                  
            this.progressiveViewerGenerator = new ProgressiveViewerGenerator(this);          
            
            this.visiblePageRange = { begin: 0, end: 0, current: 0 };//处于显示区域的页面
            this.curPageIndex = 0;            
            switch (this.layoutInfo.showMode) {
                case WebPDF.PDFView.RD_BRMODE_CONTINUOUS:
                    this.viewLayout = new SinglePageViewLayout(this.readerApp, this, this.layoutInfo);
                    break;
                default:
                    $.error("Unsupported layout mode.");
                    break;
            }               
       
            
            this.pageViewList = {};
            this.pdfDoc.pages.each(function(pdfPage, index){
                this.pageViewList[index] = new PDFPageView(this.readerApp, this, pdfPage)
            }, this);
            
            
            var defaultZoom = this.readerApp.getOptions().defaultZoom;
            
            if (typeof(defaultZoom) == "string"){
                 this.curZoomMode = defaultZoom;
            }        
            else if (!isNaN(defaultZoom)) {
                this.layoutInfo.scale = defaultZoom;
            }                        
            
            this.loadPages = _.debounce(this.loadPages, 200);       
            
            
            _.bindAll(this, "loadPages", "onPageScroll")        
 
        },    
        render: function(){         
            this.setElement(this.viewLayout.createDocViewHtml());        
            if (this.layoutInfo.showMode == WebPDF.PDFView.RD_BRMODE_CONTINUOUS_FACING) {
                this.updateTwoPageContainerWidth();
            }
            
            this.progressiveViewerGenerator.createPages(0);
            this.initializeScrollBar();
            if(this.isFitWidth()){
                this.fitWidth(true,false);
            }
            this.bindScrollEvent();
            this.onPageScroll();
            return this;
        },
         
          /**
         * Set width of doc view.
         * @param {Number} width width of doc view to set.
         * @ignore
         */
        setDocViewWidth : function (width) {
            this.docViewWidth = width;
        },
        /**
         * @description Returns the width of the current viewer.
         * @return {Number} The width of the current viewer.
         */
        getDocViewWidth : function () {
            return this.docViewWidth;
        },
        /**
         * Set width of doc view.
         * @param {Number} height width of doc view to set.
         * @ignore
         */
        setDocViewHeight : function (height) {
            this.docViewHeight = height;
        },
        /**
         * @description Returns the height of the current viewer.
         * @return {Number} The height of the current viewer.
         */
        getDocViewHeight : function () {
            return this.docViewHeight;
        },
         
        /**
         * Resize doc view.
         * @param width new width of doc view.
         * @param height new height of doc view.
         * @param offsetLeft offset of doc view in x-aixs
         * @param offsetTop offset of doc view in y-aixs
         * @ignore
         */
        onSize : function (width, height, offsetLeft, offsetTop) {
            this.unBindScrollEvent();
            //重置页面状态，这样会重新计算页面宽高和左边偏移量;
            this.resetDimensionUpdateStateOfAllPages();
            var jqDocViewContainer = this.$el;

            //这里需要将height减去边距和padding
            var paddingVertical = jqDocViewContainer.outerHeight() - jqDocViewContainer.height();
            var paddingHorizontal = jqDocViewContainer.outerWidth() - jqDocViewContainer.width();
            var docViewHeight = height - paddingVertical;
            var docViewWidth = width - paddingHorizontal;
            var docViewOffsetLeft = offsetLeft;
            var docViewOffsetTop = offsetTop;           
         
          /*  if(WebPDF.Environment.mobile){
                jqDocViewContainer.css(
                    {
                        width: _docViewWidth,
                        //  height: _docViewHeight, //comment for test mobile
                        left: offsetLeft,
                        top: offsetTop
                    }
                );
            }
            else{*/
                jqDocViewContainer.css({
                        width: docViewWidth,
                        height: docViewHeight,
                        left: offsetLeft,
                        top: offsetTop
                    });
            //}


            var oldPageIndex = this.curPageIndex;
            if (this.scrollApi) {
                this.fixCustomScrollBarPos(this.scrollApi);
            }
            if (this.isFitWidth()) {
                var newScale = this.viewLayout.getFitWidthScale(true);
                this.onZoom(newScale);
            }
            else{
                this.reinitializeScrollBar();
            }
            this.onPageScroll();
            this.bindScrollEvent();
            //保持原来的页面索引
            var pageDomElem = this.getPageView(oldPageIndex).el;
            this.scrollApi.scrollToElement(pageDomElem, true, false);
        },
         
        /**
         * Bind scroll event of doc view.
         * @private
         */
        bindScrollEvent: function() {
            this.$el.scroll(this.onPageScroll);
        },
        /**
         * Unbind scroll event of doc view.
         * @private
         */
        unBindScrollEvent : function() {
            this.$el.off("scroll");
        },
         
         /**
         * Reset dimension update state of all of pages.
         * @private
         */
        resetDimensionUpdateStateOfAllPages : function() {
            var pageCnt = this.getPageCount();
            
            _.each(this.pageViewList, function(pageView){
                if(pageView.isContentCreated())  {
                    pageView.setDimensionUpdated(false);
                }
            });           
        },       
        
         
         /**
         * Get scroll api.
         * @returns scroll api object.
         * @ignore
         */
        getScrollApi : function () {
            return this.scrollApi;
        },
         
        getScrollBarSettings : function(){                  
            var docView = this;
            var _scrollKeyDownCallback = { 
                37: function () {
                    docView.goToPrevPage();},
                33: function () {
                    docView.goToPrevPage();}, 
                39: function () {
                    docView.goToNextPage();}, 
                34: function () {
                    docView.goToNextPage();}, 
                35: function () {
                    docView.goToPage(docView.getPageCount() - 1, 0, 0);}, 
                36: function () {
                    docView.goToPage(0, 0, 0);}
            };
            return {
                showArrows: false,
                animateScroll: false,
                contentWidth: (this.readerApp.getPixelsPerPoint() * this.getMaxPDFPageWidth() *
                    this.getScale() + 0.5),
                keyDownCallback: _scrollKeyDownCallback
            };
        },
        
          /**
         * Initialize scroll bar
         * @param {Object|null|undefined} settings
         * @returns scroll api.
         * @ignore
         */
        initializeScrollBar : function (settings) {
            if (this.scrollApi){
                return this.scrollApi;
            }
            if(!settings){
                settings = this.getScrollBarSettings();
            }            
            var scrollApiElem;
            switch(this.readerApp.getOptions().scrollBarType) {
                case WebPDF.PDFView.ScrollBarType.CUSTOM_SCROLL_BAR:
                {
                    scrollApiElem = this.$el.fwrJScrollPane(settings);
                }
                break;
                case WebPDF.PDFView.ScrollBarType.NATIVE_SCROLL_BAR:
                {
                    scrollApiElem = this.$el.WebPDFNativeScroll(settings);
                }
                break;
                default: {
                    $.error("Unsupported type of scroll bar.");
                }
                break;
            }
            this.scrollApi = scrollApiElem.data('jsp');
            return this.scrollApi;
        },
        /**
         * Reinitialize scroll bar
         * @param settings
         * @ignore
         */
        reinitializeScrollBar : function (settings) {
            if (this.scrollApi == null){
               $.error('Scroll bar has not been initialized.');
            }
            this.readerApp.trigger(WebPDF.EventList.DOCVIEW_PRE_RESIZE,{});
            if (settings){
                this.scrollApi.reinitialise(settings);
            }
            else {
                this.scrollApi.reinitialise(this.getScrollBarSettings());
            }
            this.readerApp.trigger(WebPDF.EventList.DOCVIEW_RESIZE,{});
        },
       
        /**
         * Calculate scale of fit width.
         * @returns {Number} scale of fit width.
         * @ignore
         */
        getFitWidthScale : function () {
            return this.viewLayout.getFitWidthScale(true);
        },
         
        /**
         * @description Returns the number of pages in a document.
         * @return {Number} The number of the pages in the current document.
         */
        getPageCount : function () {
            return this.pdfDoc.getPageCount();
        },
         
        createPagesView : function(startIndex, endIndex, insertAfterPageIndex){
            return this.viewLayout.createPagesView(startIndex, endIndex, insertAfterPageIndex);
        },
         
        /**
         * @description Returns the PDFPageView object by index.
         * @param {Number} pageIndex The page index
         * @return {WebPDF.PDFView.PDFPageView} the PDFPageView object by index.
         */
        getPageView : function (pageIndex) {
            return this.pageViewList[pageIndex];
        },
                  
         /**
         * Returns the current zoom level.
         * @returns {Number|String} The current zoom level.
         */
        getScale : function () {
            return this.viewLayout.getScale();
        },

        /**
         * Set scale
         * @param {Number|{String}} scale
         * @ignore
         */
        setScale : function (scale) {
            this.viewLayout.setScale(scale);
        },
         
         /**
         * @description Check whether the current zoom level is "FitWidth".
         * @return {Boolean} Return true if the current zoom level is "FitWidth", otherwise return false.
         * @ignore
         */
        isFitWidth : function () {
            return this.curZoomMode == WebPDF.ZOOM_FIT_WIDTH;
        },
        
        
        isActualSize : function () {
            return this.curZoomMode == WebPDF.ZOOM_ACTUAL_SIZE;
        },
        
        
        isFitPage : function () {
            return this.curZoomMode == WebPDF.ZOOM_FIT_PAGE;
        }, 

        getLeftDocContainerID : function () {
            return this.leftDocContainerID;
        },
         
        getRightDocContainerID : function () {
            return this.rightDocContainerID;
        },
         /**
         * Page scroll event handler.
         * @private
         */
        onPageScroll : function() {
            var oldVisibleRange = this.getVisiblePageRange();
            var range = this.getVisiblePageRange();
            var lastVisiblePageIndex = range.end;
            var firstVisiblePageIndex = range.begin;
            var pageCount = this.getPageCount();
            if (this.scrollApi) {
                var offsetX = this.scrollApi.getContentPositionX();
                // 文档视图是否被修改
                var isContentUpdate = false;
                var pageViewOffsetDocView = this.viewLayout.getPageViewOffsetDocView(this.curPageIndex);
                var offsetY = pageViewOffsetDocView.y;
                // 如果当前属于显示区域的第一页的上一页还没被创建，则创建它
                if (firstVisiblePageIndex >= 1 && !this.getPageView(firstVisiblePageIndex - 1).isContentCreated()) {
                    isContentUpdate = this.progressiveViewerGenerator.createPages(firstVisiblePageIndex - 1);
                }
                // 如果当前属于显示区域的最后一页的下一页还没被创建，则创建它
                if (lastVisiblePageIndex < pageCount-1 && !this.getPageView(lastVisiblePageIndex + 1).isContentCreated()) {
                    isContentUpdate |= this.progressiveViewerGenerator.createPages(lastVisiblePageIndex + 1);
                }
                if (isContentUpdate) {
                    this.scrollApi.scrollToX(offsetX);
                }
                this.progressiveViewerGenerator.progressiveUpdatePageDimension(this.curPageIndex, firstVisiblePageIndex, lastVisiblePageIndex,
                    offsetY, true, true);
            }
            //重新计算页面显示范围
            range = this.countVisiblePageRange();
            var oldPageIndex = this.curPageIndex;
            this.curPageIndex = range.current;
            this.updatePageIndex(oldPageIndex);

            
            var newVisibleRange = this.getVisiblePageRange();
            this.notifyPageVisibleStatus(oldVisibleRange,newVisibleRange);        
            this.loadPages(range);           
            this.readerApp.trigger(WebPDF.EventList.DOCVIEW_SCROLL,{});
        },
        
        /**
         * Returns range of current visible pages.
         * @returns {{begin: number, current: number, end:number}} Range of current visible pages.
         */
        getVisiblePageRange : function () {
            return this.visiblePageRange;
        },

        /**
         * Count visible page range.
         * @returns {{begin: number, current: number, end:number}}
         * @ignore
         */
        countVisiblePageRange : function () {
            this.visiblePageRange = this.progressiveViewerGenerator.countVisiblePageRange();
            return this.visiblePageRange;
        },
                
        getRealScrollBarWidth : function(scale){
        	var scrollBarWidth = 0;
        	if (!scale) {
        		scale = this.getScale();
        	}
        	
        	if (this.scrollApi) {
        		scrollBarWidth = this.scrollApi.getScrollBarWidth();
        		if (scrollBarWidth > 0) {
        			this.scrollBarWidth = scrollBarWidth;
        		}
        		var maxPageHeight = this.getMaxPageViewHeight(false) * scale + 14/*.fwr-page margin-bottom*/;
                if ((this.getDocViewHeight() < maxPageHeight) && (scrollBarWidth <= 0)) {
                	scrollBarWidth = this.scrollBarWidth;
                } else if ((this.getDocViewHeight() > maxPageHeight) && (scrollBarWidth > 0)){
                	scrollBarWidth = 0;
                }
        	}
        	return scrollBarWidth;
        },
           /**
         * Get max height of all of page views.
         * @param {Boolean} isScale if this parameter set to true, the width will be plus current zoom level.
         * @returns {number|null|undefined} max width of all of page views.
         * @ignore
         */
        getMaxPageViewWidth : function (isScale) {
            var scale = isScale ? this.getScale() : 1;
            return this.getMaxPDFPageWidth() * this.readerApp.getPixelsPerPoint() * scale;
        },
        /**
         * Get max height of all of page views.
         * @param {Boolean} isScale if this parameter set to true, the width will be plus current zoom level.
         * @returns {number} max height of all of page views.
         * @ignore
         */
        getMaxPageViewHeight : function (isScale) {
            var scale = isScale ? this.getScale() : 1;
            return this.getMaxPDFPageHeight() * this.readerApp.getPixelsPerPoint() * scale;
        },
         
        /**
         * Get the max width of all of pages in the current document.
         * @returns {number}  the max width of all of pages in the current document.
         * @ignore
         */
        getMaxPDFPageWidth : function () {
            if (this.maxPDFPageWidth)
                return this.maxPDFPageWidth;         
            
            var maxWidth = -1;
            this.pdfDoc.pages.each(function(pdfPage){
                var width = pdfPage.getPageWidth();
                if (width > maxWidth)
                   maxWidth = width;
                })           
            this.maxPDFPageWidth = maxWidth;
            return this.maxPDFPageWidth;
        },
        /**
         *  Get the max height of all of pages in the current document.
         * @returns {number} the max height of all of pages in the current document.
         * @ignore
         */
        getMaxPDFPageHeight : function () {
            if (this.maxPDFPageHeight)
                return this.maxPDFPageHeight;   
            var maxHeight =  -1;
            this.pdfDoc.pages.each(function(pdfPage){
                  var height = pdfPage.getPageHeight();
                if (height > maxHeight)
                     maxHeight = height;
                })      
            this.maxPDFPageHeight = maxHeight;
            return this.maxPDFPageHeight;
        },
          /**
         * Update page index
         * @param oldPageIndex Old page index
         * @private
         */
        updatePageIndex : function(oldPageIndex) {
            var pageView = this.getPageView(this.curPageIndex);
            if (!pageView.isDimensionUpdated()) {
                pageView.updateDimension();
                pageView.setDimensionUpdated(true);
            }

            if (oldPageIndex != this.curPageIndex) {
                /*if (WebPDF.Environment.mobile) {
                    var jqPageIndexTooltip = $('#' + _pageIndexTooltipDivId);
                    if (_tooltipTimeout) {
                        clearTimeout(_tooltipTimeout);
                        _tooltipTimeout = null;
                        jqPageIndexTooltip.trigger('hidetooltip');
                    }
                    jqPageIndexTooltip.tinytooltip({
                        message: function () {
                            return _curPageIndex + 1 + " / " + _self.getPageCount();
                        },
                        hover: false,
                        floatRight: true
                    }).trigger('showtooltip');
                    _tooltipTimeout = setTimeout(function () {
                        jqPageIndexTooltip.trigger('hidetooltip');
                    }, 2000);
                }*/

                this.readerApp.trigger(WebPDF.EventList.DOCVIEW_PAGE_CHANGED, {oldIndex: oldPageIndex, curIndex: this.curPageIndex});
            }
        },
         
        /**
         * 触发页面显示或隐藏的事件
         * @param oldVisibleRange 变化前的页面范围
         * @param newVisibleRange 变化后的页面范围
         * @private
         */
        notifyPageVisibleStatus : function(oldVisibleRange, newVisibleRange) {
            var jqPagesContainerDiv = this.$el;
            var docViewDimension = this.getDocViewDimension();
            var contentPaneHeight = docViewDimension.height;
            var contentPanelWidth = docViewDimension.width;
            var contentPanelOffset = jqPagesContainerDiv.offset();
            var invisiblePageList = [];
            var visiblePageList = [];
            var i;
            for (i=oldVisibleRange.begin; i<=oldVisibleRange.end; i++) {
                if (i < newVisibleRange.begin || i > newVisibleRange.end) {
                    invisiblePageList.push(i);
                    this.getPageView(i).$el.addClass("fwr-page-invisible");                 
                }
            }
            for (i = newVisibleRange.begin; i <= newVisibleRange.end; i++) {
                this.getPageView(i).$el.removeClass("fwr-page-invisible");
                visiblePageList.push(i);
            }
            if(invisiblePageList.length > 0){
                this.readerApp.trigger(WebPDF.EventList.PAGE_INVISIBLE,{pages:invisiblePageList});
            }
            if(visiblePageList.length > 0){
                this.readerApp.trigger(WebPDF.EventList.PAGE_VISIBLE,
                    {
                        pages: visiblePageList,
                        contentPanelWidth: contentPanelWidth,
                        contentPaneHeight: contentPaneHeight,
                        contentPanelOffset: contentPanelOffset
                    }
                );
            }
        },
       
        /**
         * 加载指定范围内的页面
         * @param range 页面范围
         * @private
         */
        loadPages : function(range) {
            var jqPagesContainerDiv = this.$el;
            var docViewDimension = this.getDocViewDimension();
            var contentPanelHeight = docViewDimension.height;
            var contentPanelWidth = docViewDimension.width;
            var contentPanelOffset = jqPagesContainerDiv.offset();
            var scrollBarWidth = 0, scrollBarHeight = 0;
            if(this.scrollApi){
                scrollBarWidth = this.scrollApi.getScrollBarWidth();
                scrollBarHeight = this.scrollApi.getScrollBarHeight();
            }
            //多加载相邻的两页
            var startPageIndex = range.begin - 1;
            var endPageIndex = range.end + 1;
            var loadingIconWidth = 24;
            for (var i=startPageIndex; i<=endPageIndex; i++) {
                var pageView = this.getPageView(i);
                if (pageView) {
                    //处于显示范围内的页面，并且页面内容还没显示，则动态的去调整页面中loading图标的位置
                    if (i>=range.begin && i<=range.end && !pageView.isPageLoaded()) {
                        var pageWidth = pageView.getPageViewWidth(),
                            pageHeight = pageView.getPageViewHeight();
                        var jqPageContainer = pageView.$el;
                        var visibleWidth = contentPanelWidth;
                        var visibleHeight = contentPanelHeight;
                        if (this.scrollApi) {
                            visibleHeight -= scrollBarHeight;
                            visibleWidth -= scrollBarWidth;
                        }
                        var pageOffset = jqPageContainer.offset();

                        var bottomOverflow = pageOffset.top + pageHeight - (contentPanelOffset.top + visibleHeight);
                        if (bottomOverflow < 0){
                            bottomOverflow = 0;
                        }
                        var topOverflow = 0;
                        if (pageOffset.top < contentPanelOffset.top) {
                            topOverflow = contentPanelOffset.top - pageOffset.top;
                        }
                        var leftOverflow = contentPanelOffset.left - pageOffset.left;
                        if (leftOverflow < 0){
                            leftOverflow = 0;
                        }
                        var rightOverflow = pageOffset.left + pageWidth - (contentPanelOffset.left + visibleWidth);
                        if (rightOverflow < 0)  {
                            rightOverflow = 0;
                        }
                        var jqLoadingDiv = pageView.getPageLoaderImage();

                        if (jqLoadingDiv.length > 0) {
                            //页面显示区域小于loading图片大小
                            if (pageHeight - bottomOverflow - topOverflow < loadingIconWidth) {
                                bottomOverflow = 0;
                                topOverflow = 0;
                            }
                            jqLoadingDiv.css(
                                {
                                    marginLeft: -loadingIconWidth/2 - (rightOverflow - leftOverflow) / 2,
                                    marginTop: -loadingIconWidth/2 - (bottomOverflow - topOverflow) / 2
                                }
                            );
                        }
                    }
                                       
                    this.pageViewRender.renderPage(pageView, Config.defaults.requestRetryCount);
                }
            }
        },
        
         
        /**
         * Get dimension of doc view.
         * @returns {{width: number, height: number}}
         * @ignore
         */
        getDocViewDimension : function(){
            return {width: (this.docViewWidth + this.paddingHorizontal), height: (this.docViewHeight + this.paddingVertical)};
        },
         
        //防止滚动条处于负值状态，放大是页面位置错误问题;
        fixCustomScrollBarPos : function(scrollApi){
            //对于自定义滚动，防止滚动条处于负值状态，放大时页面位置错误问题;
            if(this.readerApp.getOptions().scrollBarType === WebPDF.PDFView.ScrollBarType.CUSTOM_SCROLL_BAR) {
                this.scrollApi.getContentPane().css({ left: 0 });
            }
        },
         
         /**
         * @description Jump to a page.
         * @param {Number} pageIndex page index.
         * @param {Number|null|undefined} offsetX offset in x-axis.
         * @param {!Number|null|undefined} offsetY offset in y-axis.
         * @ignore
         */
        goToPage : function (pageIndex, offsetX, offsetY) {
            if (!this.scrollApi) {
                return false;
            }
            
            var pageCount = this.getPageCount();
            if (pageIndex<0 || pageIndex >=pageCount){
                return false;
            }
            
            var oldVisibleRange = this.getVisiblePageRange();
            //先取消监控滚动事件;
            this.unBindScrollEvent();
            offsetY = offsetY ? offsetY : 0;
            if (offsetX == null){
                offsetX = this.scrollApi.getContentPositionX();
            }
            
            var maxNewPagesPerTime = Config.defaults.maxNewPagesPerTime;
            if (maxNewPagesPerTime === -1) {
                maxNewPagesPerTime = pageCount;
            }
            //如果刚好是一块页面区域的最后一页，则创建下一页的页面区域的所有页面
            if ((pageIndex + 1) % maxNewPagesPerTime === 0) {
                this.progressiveViewerGenerator.createPages(pageIndex + 1);
                this.progressiveViewerGenerator.createPages(pageIndex);
            }
            else {
                var pageToCreate = pageIndex + 1;
                if (pageToCreate >= pageCount){
                    pageToCreate = pageCount - 1;
                }
                this.progressiveViewerGenerator.createPages(pageToCreate);
            }
            var oldPageIndex = this.curPageIndex;
            this.curPageIndex = pageIndex;
            var pageDomElem = this.getPageView(pageIndex).el;
            this.scrollApi.scrollToElement(pageDomElem, true, false, offsetY);
            this.scrollApi.scrollToX(offsetX);
            if (this.progressiveViewerGenerator.progressiveUpdatePageDimension(pageIndex, _curPageIndex, _curPageIndex, offsetY, true, true)) {
                this.countVisiblePageRange();
            }
            this.countVisiblePageRange();

            this.progressiveViewerGenerator.createAdjacentPage(pageIndex, offsetY);
            var newVisibleRange = this.getVisiblePageRange();
            this.curPageIndex = newVisibleRange.current;
            this.updatePageIndex(oldPageIndex);
            this.loadPages(newVisibleRange);
            this.notifyPageVisibleStatus(oldVisibleRange,newVisibleRange);
            this.bindScrollEvent(); //恢复监控滚动事件
           /* if($.support.touch){
                _onPageScroll();
            }*/
            return true;
        },

        /**
         * @description Go to next page.
         * @ignore
         */
        goToNextPage : function () {
            if (this.curPageIndex >= this.getPageCount()-1)
                return;
            this.goToPage(this.curPageIndex + 1);
            /*if($.support.touch){
                _onPageScroll();
            }*/
        },

        /**
         * @description Go to previous page.
         * @ignore
         */
        goToPrevPage : function () {
            if (this.curPageIndex <= 0)
                return;
            this.goToPage(this.curPageIndex - 1);
           /* if($.support.touch){
                _onPageScroll();
            }*/
        },

        /**
         * Goto page by destination info
         * @param {WebPDF.PDFData.PDFDestination} destInfo destination info
         * @ignore
         */
        goToPageByDestination : function (destInfo) {
            var pageCount = this.getPageCount();
            if (!destInfo || destInfo.pageIndex < 0 || destInfo.pageIndex >= pageCount) {
                return;
            }
            var pixelsPerPoint = this.readerApp.getPixelsPerPoint();
            this.viewLayout.zoomToPage(destInfo.zoomToMode, destInfo.scale, destInfo.width * pixelsPerPoint,
                    destInfo.height * pixelsPerPoint, true);

            var destTop = 0;
            var destLeft = 0;
            if (destInfo.top !== -1) {
                destTop = destInfo.top * this.layoutInfo.scale * pixelsPerPoint;
            }
            if (destInfo.left !== -1) {
                destLeft = destInfo.left * this.layoutInfo.scale * pixelsPerPoint;
            }
            this.goToPage(destInfo.pageIndex, destLeft, destTop);
        },
        
        /**
         * Check whether doc content has been modified.
         * @returns {boolean} return true if page doc has been modified.
         * @ignore
         */
        isModified : function () {
            return this._isModified;
        },
        /**
         * Set state of doc content modification.
         * @param{Boolean} isModified
         * @ignore
         */
        setModified : function (isModified) {
            this._isModified = isModified;          
            this.readerApp.trigger(WebPDF.EventList.DOC_MODIFY_STATE_CHANGED, isModified);
        },        
                                                
        getDocViewContainerID : function () {
            return this.docViewContainerID;
        },
        /**
         * @description Returns the current page number.
         * @return {Number}  The current 0-indexed page number.
         */
        getCurPageIndex : function () {
            return this.curPageIndex;
        },
       

        /**
         * Returns the id of DOM element for a page.
         * @param pageIndex the page index.
         * @returns {string} the id of DOM element for a page.
         * @ignore
         */
        getPageViewContainerID : function (pageIndex) {
            return this.docViewContainerID + "_PageContainer_" + pageIndex.toString();
        },
        /**
         * Get id of background image by page index.
         * @param pageIndex page index
         * @returns {string}
         * @ignore
         */
        getPageBackgroundImgID : function (pageIndex) {
            return this.docViewContainerID + "_BG_" + pageIndex.toString();
        },
        /**
         * 根据页面索引，获取对应页面Wrap ID，主要用于页面加载失败的情况下显示一些信息在这个div下面
         * @param pageIndex page index
         * @returns {string}
         * @ignore
         */
        getWrapPageID : function (pageIndex) {
            return this.docViewContainerID + "_Wrap_" + pageIndex.toString();
        },
        /**
         * Get id of loader image.
         * @param pageIndex page index.
         * @returns {string}
         * @ignore
         */
        getPageLoaderImageID : function (pageIndex) {
            return this.docViewContainerID + "_Loader_" + pageIndex.toString();
        },
        /**
         * @description Returns the Document that is currently being displayed by the viewer.
         * @return {WebPDF.IPDFDocument} The PDF document object.
         */
        getPDFDoc : function () {
            return this.pdfDoc;
        },
        /**
         * @description Returns the number of pages in a document.
         * @return {Number} The number of the pages in the current document.
         */
        getPageCount : function () {
            return this.pdfDoc.getPageCount();
        },        
        /**
         * Get page view render.
         * @returns {WebPDF.IPageViewRender}
         * @ignore
         */
        getPageViewRender : function () {
            return this.pageViewRender;
        },
       

        setDocViewOffsetLeft : function (docViewOffsetLeft) {
            this.docViewOffsetLeft = docViewOffsetLeft;
        },
        getDocViewOffsetLeft : function () {
            return this.docViewOffsetLeft;
        },
        setDocViewOffsetTop : function (docViewOffsetTop) {
            this.docViewOffsetTop = docViewOffsetTop;
        },
         
        getDocViewOffsetTop : function () {
            return this.docViewOffsetTop;
        },

        /**
         * @description Get the rectangle area of the current viewer.
         * @return {WebPDF.PDFRect} The rectangle of the current viewer.
         */
        getDocViewClientRect : function () {
            var docOffsetHtmlDoc = this.$el.offset();
            var docViewDimension = this.getDocViewDimension();
            var docViewRect = new PDFRect(docOffsetHtmlDoc.left, docOffsetHtmlDoc.top,
                    docOffsetHtmlDoc.left + docViewDimension.width, docOffsetHtmlDoc.top + docViewDimension.height);
            WebPDF.RectUtils.normalize(docViewRect);
            return docViewRect;
        },
        
     

        /**
         * @description Set current zoom level to "FitWidth".
         * @param isForce whether to update zoom level even if current zoom level is already "FitWidth"
         * @ignore
         */
        fitWidth : function (isForce, isTriggerEvent) {                                        
            if (!isForce && _curZoomMode == WebPDF.ZOOM_FIT_WIDTH)
                return;
            _curZoomMode = WebPDF.ZOOM_FIT_WIDTH;
            var scale = _viewLayout.getFitWidthScale(true);
            this.onZoom(scale,isTriggerEvent);       
        },
        
        fitPage : function(isForce, isTriggerEvent){
            if (!isForce && this.curZoomMode == WebPDF.ZOOM_FIT_PAGE)
                return;
            this.curZoomMode = WebPDF.ZOOM_FIT_PAGE;
            var scale = this.viewLayout.getFitPageScale();
            this.onZoom(scale,isTriggerEvent);
        },

        actualSize : function(isForce, isTriggerEvent){
            if (!isForce && this.curZoomMode == WebPDF.ZOOM_ACTUAL_SIZE)
                return;
              
            this.curZoomMode = WebPDF.ZOOM_ACTUAL_SIZE;           
            var scale = 1.0;
            this.onZoom(scale, isTriggerEvent);    
        },
        
        
        fitVisible : function(isForce, isTriggerEvent){
            if (!isForce &&  this.curZoomMode == WebPDF.ZOOM_FIT_VISIBLE)
                return;   
            this.curZoomMode = WebPDF.ZOOM_FIT_VISIBLE;               
        },
        
        /**
         * Get current zoom list.
         * @returns {Array.<Number>} zoom list.
         * @ignore
         */
        getCurrentZoomList : function() {    
            var defaultList =  Config.defaults.zoomList.sort();         
            var zoomList = [];          
            for(var i=0; i < defaultList.length; i++){
                var val = defaultList[i]
                zoomList.push({key: val*100, value:val * 100 + '%'});
            }         
            zoomList.push({key:WebPDF.ZOOM_ACTUAL_SIZE, value:WebPDF.ZOOM_ACTUAL_SIZE});
            zoomList.push({key:WebPDF.ZOOM_FIT_WIDTH, value:WebPDF.ZOOM_FIT_WIDTH});
            zoomList.push({key:WebPDF.ZOOM_FIT_PAGE, value:WebPDF.ZOOM_FIT_PAGE});                
            return zoomList;       
        },
        
        
        getCurrentScaleList : function() {      
            var zoomList =   Config.defaults.zoomList.concat();           
            var fitWidthScale = this.viewLayout.getFitWidthScale(true);
            var fitPageScale =  this.viewLayout.getFitPageScale();          
            zoomList.push(fitWidthScale);
            zoomList.push(fitPageScale);     
            zoomList.sort();         
            return zoomList;           
        },
        
        curZoomMode : function(){
            return this.curZoomMode;
        },       
        
        setCurZoomMode : function(zoomMode){
            this.curZoomMode = zoomMode;
        },
        /**
         * Zoom in
         * @ignore
         */
        zoomIn : function(){
            var curZoom = this.getScale();                       
            var zoomList = this.getCurrentScaleList();
            var currentZoomIndex = -1;
            for (var i=0; i<zoomList.length; i++) {
                var zoom = zoomList[i];                
                if (zoom > curZoom){
                    curZoom = zoom;
                    break;
                }               
            }            
            this.curZoomMode = WebPDF.ZOOM_NUMBER;
            this.onZoom(curZoom);           
        },

        /**
         * Zoom out
         * @ignore
         */
        zoomOut : function(){
            var curZoom = this.getScale();                 
            var zoomList = this.getCurrentScaleList();        
            for (var i= zoomList.length-1; i>-1; i--) {
                var zoom = zoomList[i];                
                if (zoom < curZoom){
                    curZoom = zoom;
                    break;
                }               
            }            
            this.curZoomMode = WebPDF.ZOOM_NUMBER;
            this.onZoom(curZoom);     
        },

        updateTwoPageContainerWidth : function () {
            var maxWidth = this.getMaxPageViewWidth(true);
            var containerWidth = this.$el.width();
            maxWidth = maxWidth > containerWidth ? maxWidth : containerWidth;
            $("#" + this.getLeftDocContainerID()).css("width", maxWidth / 2);
            $("#" + this.getRightDocContainerID()).css("width", maxWidth / 2).css("left", maxWidth / 2);
        },

     
        /**
         * Get view mode.
         * @returns {number}
         * @ignore
         */
        getViewMode : function () {
            return this.layoutInfo.showMode;
        },  

       

        /**
         * @description Scrolls view.
         * @param {Number} offsetX   offset in x-axis.
         * @param {Number} offsetY   offset in y-axis.
         * @ignore
         */
        movePage : function (offsetX, offsetY) {
            if (this.scrollApi != null) {
                this.scrollApi.scrollBy(offsetX, offsetY);
            }
        },

        

        

        /**
         * Zoom the page according to the specified zoom level and position.
         * @param scale zoom level
         * @param pageX x-axis of click/touch position.
         * @param pageY y-axis of click/touch position.
         * @param pageIndex page index
         * @ignore
         */
        onZoomByPos : function (scale, pageX, pageY, pageIndex){
            var oldScale = this.viewLayout.getScale();
            var scaleMultiple = scale / oldScale;
            var jqPageView = this.getPageView(pageIndex).$el;
            var docPositionHtmlDoc = jqPageView.position();
            var docOffsetHtmlDoc = jqPageView.offset();
            var docViewWidth = this.getDocViewWidth();
            var docViewHeight = this.getDocViewHeight();
            var pageViewRect = new PDFRect(docOffsetHtmlDoc.left, docOffsetHtmlDoc.top,
                    docOffsetHtmlDoc.left + docViewWidth, docOffsetHtmlDoc.top + docViewHeight);
            var oldOffsetX = pageX - pageViewRect.left;
            var oldOffsetY = pageY - pageViewRect.top;

            this.viewLayout.setScale(scale);
            this.resetDimensionUpdateStateOfAllPages();
            //_resetPageLoadedState();
            var oldPagePageIndex = this.curPageIndex;
            this.onPageScroll();
            this.curPageIndex = oldPagePageIndex;
            this.updatePageIndex(oldPagePageIndex);

            this.scrollApi.scrollToElement(jqPageView[0], true, false);
            this.scrollApi.scrollBy(oldOffsetX * (scaleMultiple - 1) - docPositionHtmlDoc.left,
                    oldOffsetY * (scaleMultiple - 1) - docPositionHtmlDoc.top);
            this.readerApp.trigger(WebPDF.EventList.DOCVIEW_ZOOM_CHANGED,{oldScale:oldScale, newScale:scale});
        },

        

        /**
         * Zoom the page according to the specified zoom level.
         * @param scale zoom level
         * @ignore
         */
        onZoom : function (scale,isTriggerEvent) {
            var oldScale = this.viewLayout.getScale();
            if (scale === oldScale) {
                return;
            }                       
            var fitWidthScale = this.viewLayout.getFitWidthScale(true);
            var fitPageScale =  this.viewLayout.getFitPageScale();   
          
            if (scale == fitWidthScale){
                this.curZoomMode = WebPDF.ZOOM_FIT_WIDTH;   
            }
            else if (scale == fitPageScale){
                this.curZoomMode = WebPDF.ZOOM_FIT_PAGE;
            }
            this.unBindScrollEvent();
            this.viewLayout.setScale(scale);
            //重置页面状态，这样会重新计算页面宽高和左边偏移量;
            this.resetDimensionUpdateStateOfAllPages();
            //_resetPageLoadedState();
            var oldPageIndex = _curPageIndex;
            if (this.scrollApi)  {
                this.fixCustomScrollBarPos(this.scrollApi);
            }
            this.onPageScroll();
            //解决更新之后没有滚动条时，但是top不为0，导致无法显示页面
            //if(_scrollApi.getIsScrollableV()){
				if(this.readerApp.getOptions().scrollBarType === WebPDF.PDFView.ScrollBarType.CUSTOM_SCROLL_BAR) {
					this.scrollApi.getContentPane().css({ top: 0 });
				}
	       	//}
            
            //保持原来的页数;
            var pageDomElem = this.getPageView(oldPageIndex).el;
            this.scrollApi.scrollToElement(pageDomElem, true, false);
            this.curPageIndex = oldPageIndex;
            this.bindScrollEvent();
            this.updatePageIndex(oldPageIndex);
            if(isTriggerEvent === true)
            {
                this.readerApp.trigger(WebPDF.EventList.DOCVIEW_ZOOM_CHANGED,{oldScale:oldScale, newScale:scale});
            }
        }        
    });

    return PDFDocView;
});